package org.dezenho.server.RN;

import java.awt.Point;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.dezenho.server.IP.PalavraIP;
import org.dezenho.server.SO.DezenhoServer;

/**
 * Classe responsavel por representar e controlar uma rodada de uma partida
 * e ainda controlar a sequencia de fim de partida e inicio de uma nova
 * @author marcelasobrinhopereira
 *
 */
public class Rodada {

	private Temporizador temporizador;
	private String palavra;
	private int multiplicador;
	private Jogador acertador;
	private Point[] desenho;
	private Partida partida;
	private Jogador desenhista;
	private String IpUltimoJogadorAcessado = new String();

	/**
	 * Construtor
	 * @param Partida a que pertence
	 */
	public Rodada(Partida partida) {
		setPartida(partida);
	}

	/**
	 * Metodo que sincroniza desenhsta e adivinhadores
	 * e verifica se a rodada acabou por fim do tempo ou acerto de palavra
	 */
	public void controlaRodada() {

		Thread t = new Thread() {
			public void run() {
				// Variaveis locais
				List<Jogador> adivinhadores = new ArrayList<Jogador>();
				try {
					getTemporizador().iniciaContador();

					for (Jogador jogador : getPartida().getJogadores()) {
						if (jogador.getPapel() == TipoJogador.DESENHINSTA)
							setDesenhista(jogador);
						else
							adivinhadores.add(jogador);
					}
					while ((getTemporizador().calculaTempoRestante() > 0)
							&& (getAcertador() == null)) {
						setDesenho(atualizaDesenhista());
						atualizaAdivinhadores(adivinhadores);
					}

					contablizaPlacar();
					apresentaResultadoRodada();
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					getPartida().iniciaRodada();
				} catch (RemoteException e) {
					DezenhoServer.getInstance().desconectaUsuario(
							getIpUltimoJogadorAcessado());
				}
			}

		};
		t.start();
	}

	/**
	 * Prepara a rodada setando as propiedades importantes
	 * e Inicializa os jogadores
	 */
	public void iniciaNovaRodada() {
		sorteiaPalavraMultiplicador();
		setTemporizador(new Temporizador());
		inicializaJogadores();
	}

	/**
	 * Sorteia Aleatoriamente palavra e multiplicador
	 */
	private void sorteiaPalavraMultiplicador() {
		try {
			Random geradorAleatorio = new Random();
			setMultiplicador(geradorAleatorio.nextInt(5) + 1);
			PalavraIP palavraBD = new PalavraIP();
			setPalavra(palavraBD.lerPalavra(geradorAleatorio.nextInt(palavraBD
					.lerTotalPavras())));
		} catch (Exception e) {
			System.out.println("Erro na comnicacao com o banco");
		}
	}

	/**
	 * Pede para que o cliente inicialize a tela de Desenhita ou adivinhador
	 * enviando os parametros necessario
	 */
	private void inicializaJogadores() {
		for (Jogador jogador : getPartida().getJogadores()) {
			try {
				if (jogador.getPapel() == TipoJogador.DESENHINSTA)
					jogador.getClient().inicializaDesenhista(
							getTemporizador().getTempoTotal(), getPalavra(),
							getMultiplicador(), getPartida().getIdPartida());
				else
					jogador.getClient().inicializaAdivinhador(
							getTemporizador().getTempoTotal(), getPalavra(),
							getMultiplicador());
			} catch (RemoteException e) {
				DezenhoServer.getInstance().desconectaUsuario(
						jogador.getIPUsuario());
			}
		}
	}

	/**
	 * Atualiza o tempo restante do desenhista
	 * e busca o desenho atual
	 * @param Point[] desenho atualizado
	 */
	private Point[] atualizaDesenhista() throws RemoteException {
		setIpUltimoJogadorAcessado(getDesenhista().getIPUsuario());
		return getDesenhista().getClient().atualizaDesenhista(
				getTemporizador().calculaTempoRestante());
	}

	/**
	 * Atualiza jogadores com o tempo restante e o desenho atualizado
	 */
	private void atualizaAdivinhadores(List<Jogador> adivinhadores)
			throws RemoteException {
		for (Jogador adivinhador : adivinhadores) {
			if (adivinhador.getClient().atualizaAdivinhador(
					getTemporizador().calculaTempoRestante(), getDesenho()) == true) {
				setIpUltimoJogadorAcessado(adivinhador.getIPUsuario());
				setAcertador(adivinhador);
			}
		}
	}

	/**
	 * Calcula a pontuacao dos jogadores ao fim da rodada
	 */
	private void contablizaPlacar() {
		getPartida().getPlacar().contabilizaPlacar(this);
	}

	/**
	 * Pede para que os clientes exibam o resultado da roda
	 * que e enviado como parametro
	 * @throws RemoteException
	 */
	private void apresentaResultadoRodada() throws RemoteException {
		Map<String, Integer> pontuacao = new HashMap<String, Integer>();
		for (Jogador jogador : getPartida().getJogadores())
			pontuacao.put(jogador.getNome(), jogador.getPontuacao());
		for (Jogador jogador : getPartida().getJogadores()) {
			setIpUltimoJogadorAcessado(jogador.getIPUsuario());
			if (getAcertador() != null) {
				jogador.getClient().apresentaResultadoRodada(pontuacao,
						getAcertador().getNome());
			} else {
				jogador.getClient().apresentaResultadoRodada(pontuacao,
						"Ninguem");
			}
		}

	}

	// Metodos de acesso

	public Temporizador getTemporizador() {
		return temporizador;
	}

	protected void setTemporizador(Temporizador temporizador) {
		this.temporizador = temporizador;
	}

	protected String getPalavra() {
		return palavra;
	}

	protected void setPalavra(String palavra) {
		this.palavra = palavra;
	}

	public int getMultiplicador() {
		return multiplicador;
	}

	protected void setMultiplicador(int multiplicador) {
		this.multiplicador = multiplicador;
	}

	public Jogador getAcertador() {
		return acertador;
	}

	protected void setAcertador(Jogador acertador) {
		this.acertador = acertador;
	}

	protected Point[] getDesenho() {
		return desenho;
	}

	protected void setDesenho(Point[] desenho) {
		this.desenho = desenho;
	}

	protected Partida getPartida() {
		return partida;
	}

	protected void setPartida(Partida partida) {
		this.partida = partida;
	}

	public Jogador getDesenhista() {
		return desenhista;
	}

	protected void setDesenhista(Jogador desenhista) {
		this.desenhista = desenhista;
	}

	protected String getIpUltimoJogadorAcessado() {
		return IpUltimoJogadorAcessado;
	}

	protected void setIpUltimoJogadorAcessado(String ipUltimoJogadorAcessado) {
		IpUltimoJogadorAcessado = ipUltimoJogadorAcessado;
	}

}
